www.gusucode.com > Smart Nanosatellite Attitude Propagator (SNAP) 程序工具箱matlab源码 > Smart Nanosatellite Attitude Propagator (SNAP)/libastro/read_tloes.m
function y = read_tloes(fname) %READ_TLOES Reads NORAD-style satellite orbit prediction data files % READ_TLOES(FNAME) parses a standard NORAD "two-line orbital % element set" (TLOES) data set in file FNAME. Returns an array % of structures, one structure per satellite description contained % in the file. % % Each structure contains the following fields: % .name Satellite name % .satnum Satellite number in NORAD SatCat % .classification U (unclassified) or C (classified) % .designator A structure describing International data: % .year, .launch, .piece % .epoch A structure describing the measurement epoch: % .year, .day (including fractional part) % .motion A structure describing change in mean motion: % .dt1 (1st deriv), .dt2 (2nd deriv) % .drag Ballistic coefficient of drag % .ephemeris Ephemeris model, general set to 0 % .element Element number % .inclination Inclination, degrees % .RAAN Right ascension of ascending node, degrees % .eccentricity Eccentricity % .argp Argument of perigee % .mean_anomaly In degrees % .mean_motion Revolutions per day % .revnum Satellite revolution number at epoch % % For reference, see: % http://www.amsat.org % http://www.celestrak.com % % A web search on "NORAD two-line element sets" produces excellent links as well % D. Orofino, The MathWorks, MATLAB File Exchange, updated November 2001 fid = open_file(fname); i=0; while ~feof(fid), [next,msg] = read_tle(fid); if ~isempty(msg), disp(msg); fprintf('Skipping satellite entry.\n\n'); else if ~isempty(next), i=i+1; y(i)=next; end end end % -------------------------------------------------------- function [fid,msg] = open_file(fname) fid=fopen(fname,'rt'); if fid==-1, error('File not found.'); end % -------------------------------------------------------- function [y,msg] = read_tle(fid) y=[]; msg=''; % Read in next 3 non-blank lines % for i=1:3, [c{i},valid] = read_next_nonempty_line(fid,i); if isempty(c{i}), return; end c{i}=deblank(c{i}); if ~valid, msg='Invalid characters found.'; if i>1, % can append more info msg=[msg ' Satellite name "' c{1} '"']; end return; end end % Parse first line (line "0") % ---------------- y.name = deblank(c{1}); if length(y.name)>24, fprintf('Nonstandard satellite name ("%s") exceeds 24 characters in length.\n\n',y.name); end % Parse second line (line "1") % ---------------- % 1: TLE line number, column 1 % 2: satellite number (NORAD SATCAT catalog number) and classification % NNNNNC % number is in columns 3-7 % classificatin is column 8 % where C is a classification letter: U=unclassified, S=secret % 3: International designator % YYNNNPPP, YY=last 2 digits of launch year, NNN=launch number of year, PPP=piece of launch % columns 10-11, 12-14, and 15-17 % 4: Epoch date % YYDDD.DDDDDDD, YY=last 2 digits of epoch year, D=day of year including fractional portion % columns 19-20, 21-32 % 5: First time derivative of mean motion, divided by 2, in revolutions per (day^2) % columns 34-43 % 6: Second time derivative of mean motion, divided by 6, in revs / (day^3) % columns 45-52 % 7: BSTAR drag term (ballistic coefficient), or radiation coefficient % columns 54-61 % 8: Ephemeris type (orbital prediction model) % column 63 % 1=SGP, 2=SGP4, 3=SDP4, 4=SGP8, 5=SDP8, but is usually set to 0 % 9: Element number and checksum % EEEEC EEEE=element number, C=checksum % columns 65-68, 69 line1=c{2}; if length(c{2})~= 69, msg = ['Incorrect length of line 1 for satellite "' y.name '".']; return end % 1: TLE line number linenum=str2num(line1(1)); if linenum~=1, msg = ['Invalid line number encountered on first line of data for satellite "' y.name '".']; return end % 2: satellite number and classification % NNNNNU, U=unclassified s=line1(3:7); y.satnum=str2num(s); if isempty(y.satnum), msg = ['Invalid satellite number encountered for satellite "' y.name '".']; return end y.classification = line1(8); % 3: International designator % YYNNNPPP, YY=last 2 digits of launch year, NNN=launch number of year, PPP=piece of launch y.designator.year=str2num(line1(10:11)); y.designator.launch=str2num(line1(12:14)); y.designator.piece=fliplr(deblank(fliplr(deblank(line1(15:17))))); % 4: Epoch date % YYDDD.DDDDDDD, YY=last 2 digits of epoch year, D=day of year including fractional portion y.epoch.year_trunc = str2num(line1(19:20)); % truncated (2-digit) year if y.epoch.year_trunc >= 57, century = 1900; else century=2000; end y.epoch.year=y.epoch.year_trunc + century; y.epoch.day = str2num(line1(21:32)); % 5: First time derivative of mean motion y.motion.dt1=str2num(line1(34:43)); % 6: Second time derivative of mean motion snum=fliplr(deblank(fliplr(deblank(line1(45:50))))); exp=str2num(line1(51:52)); if isempty(exp), exp=0; end % fac is a factor that moves the decimal point to start of number, % and takes into account the additional power-of-ten (sexp) fac = 10.^(-length(snum) + exp); y.motion.dt2=str2num(snum)*fac; % 7: BSTAR drag term / radiation coeff snum=fliplr(deblank(fliplr(deblank(line1(54:59))))); exp=str2num(line1(60:61)); if isempty(exp), exp=0; end % fac is a factor that moves the decimal point to start of number, % and takes into account the additional power-of-ten (sexp) % fac = 10.^(-length(snum) + exp); y.drag=str2num(snum)*fac; % 8: Ephemeris type y.ephemeris=str2num(line1(63)); % 9: Element number and checksum % EEEEC EEEE=element number, C=checksum y.element=str2num(line1(65:68)); checksum.first=str2num(line1(69)); % Verify first checksum, against two possible check values: chks=compute_checksum(c{2}); if ~any(checksum.first == chks), msg = ['Checksum on first line for satellite "' y.name '" does not match computed value.']; return end % Parse thirdline (line "2") % --------------- % 1: TLE line number, column 1 % 2: satellite number % NNNNN, column 3-7 % 3: inclination (degrees) % NNN.NNNN, col 9-16 % 4: right ascension of ascending node (RAAN) (degrees) % NNN.NNNN, col 18-25 % 5: eccentricity, leading decimal assumed % NNNNNNN, col 27-33 % 6: argument of perigee (argp) (degrees) % NNN.NNNN, col 35-42 % 7: mean anomaly degrees) % NNN.NNNN, col 44-51 % 8: mean motion (revs per day) (NN.NNNNNNN), % revolution number at epoch (RRRRR), % and checksum (C) % NN.NNNNNNNNRRRRRC, col 53-63, 64-68, 69 % (14 digits after decimal point) line2=c{3}; if length(c{3})~= 69, msg = ['Incorrect length of line 2 for satellite name "' y.name '".']; return end % 1: TLE line number linenum=str2num(line2(1)); if linenum ~= 2, msg = 'Invalid line number encountered.'; return end % 2: satellite number % NNNNN, col 3-7 satnum=str2num(line2(3:7)); if isempty(satnum), msg = 'Invalid satellite number encountered.'; return end if satnum ~= y.satnum, msg = 'Satellite number changed from line 1 to line 2 of data set.'; return end % 3: inclination (degrees) % NNN.NNNN, col 9-16 y.inclination = str2num(line2(9:16)); % 4: right ascension (degrees) % NNN.NNNN, col 18-25 y.RAAN = str2num(line2(18:25)); % 5: eccentricity, leading decimal assumed % NNNNNNN, col 27-33 snum=fliplr(deblank(fliplr(deblank(line2(27:33))))); % fac is a factor that moves the decimal point to start of number, % and takes into account the additional power-of-ten (sexp) fac = 10.^(-length(snum)); y.eccentricity = str2num(snum)*fac; % 6: argument of perigee (argp) (degrees) % NNN.NNNN, col 35-42 y.argp = str2num(line2(35:42)); % 7: mean anomaly (degrees) % NNN.NNNN, col 44-51 y.mean_anomaly = str2num(line2(44:51)); % 8: mean motion (revs per day) (NN.NNNNNNN), % revolution number at epoch (RRRRR), % and checksum (C) % NN.NNNNNNNNRRRRRC, col 53-63, 64-68, 69 % (14 digits after decimal point) y.mean_motion=str2num(line2(53:63)); y.revnum = str2num(line2(64:68)); checksum.second=str2num(line2(69)); % Verify second checksum: chks=compute_checksum(c{3}); if ~any(checksum.second == chks), msg = ['Checksum on second line for satellite "' y.name '" does not match computed value.']; return end % ----------------------------------- function chk = compute_checksum(str) % Checksum is modulo-10 sum of line content % Add numbers on line, ignoring all spaces, letters, periods, + signs % minus signs take the value of "1" % % Returns vector of two possible check sums, according to % two slightly differing algorithms str=str(1:end-1); % remove checksum value itself! nstr=fix(str); n0=fix('0'); n9=fix('9'); inum=find( (nstr >= n0) & (nstr<=n9)); iminus=find(str=='-'); digits = sum(nstr(inum)-n0); minuses = length(iminus); % count '1' for each minus sign chk1 = mod(digits+minuses,10); % We compute a second checksum according to a modified rule: iplus = find(str=='+'); pluses = length(iplus); chk2 = mod(digits+minuses+2*pluses, 10); chk = [chk1 chk2]; % ----------------------------------------------- function [next_line,valid] = read_next_nonempty_line(fid,linenum) % Read next 3 text lines from file next_line=''; while isempty(next_line) & ~feof(fid), next_line=fgetl(fid); end if linenum>1, valid = has_valid_chars(next_line); else valid = 1; % any chars valid for line 1 (sat name) end % ----------------------------------------------- function y = has_valid_chars(str) % Valid chars in a line include only the following: % [0-9 A-Z period space + -] (brackets not included!) islett = isletter(str); isnumber = ((str>='0') & (str<='9')); ispunct = (str==' ') | (str=='.') | (str=='+') | (str=='-'); y = all(islett | isnumber | ispunct); % [EOF] read_tloes.m